package com.dianban.plugin.weixinpay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dianban.base.ResultCode;
import com.dianban.base.ResultVo;
import com.dianban.utils.MD5Utils;
import com.dianban.weixin.util.WeiXinUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 语雀API文档地址:https://www.yuque.com/leshuazf/doc
 * 进件key：17B10781A8C5178870197906F71749D8
 * 交易key：a1613a0e7cb9d3a51e33784ee4d212ac
 * 验证签名工具地址：https://jh.leshuazf.com/#/signature
 * <p>
 * 服务商编号：10
 * 测试商户号号：0000000018
 * 进件接口域名:http://t-saas-mch.lepass.cn/apiv2
 * 交易接口:https://t-paygate.lepass.cn/cgi-bin/lepos_pay_gateway.cgi
 * <p>
 * ****注意事项****
 * 1.不要支付大额度，会实时扣款（限制最大金额2.00元）
 * 2.所有涉及到金额的单位都位分，币种为RMB，最小为1分，不允许出现小数
 * 3.交易需用提供的测试商户号测试
 * 4.小程序、公众号需在正式环境验证(测试环境不支持)
 */
@Component("SljLeshuaPayAppletPlugin")
public class SljLeshuaPayAppletPlugin {

    private Logger logger = LoggerFactory.getLogger(SljLeshuaPayAppletPlugin.class);

    //测试环境域名：https://t-paygate.lepass.cn
    //生产环境域名：https://paygate.leshuazf.com
    //统一下单接口地址：/cgi-bin/lepos_pay_gateway.cgi

    private final String micropayUrl = "https://paygate.leshuazf.com/cgi-bin/lepos_pay_gateway.cgi";

    @Value("${leshua.merchant_id}")
    private String merchantId;
    @Value("${leshua.appSecret}")
    private String appSecret;
    @Value("${leshua.returnAppSecret}")
    private String returnAppSecret;
    @Value("${wechat.shaliangjie.app_id}")
    private String appId;
    @Value("${wechat.shaliangjie.secret}")
    private String smallSecret;

    public String getSiteUrl() {
        //return "http://yun.dianbang-st.com:9006/api/nengliang/wechat/asyncNotify/";
        return "https://rongyaotupay.aokxm.com/api/nengliang/wechat/leshua/asyncNotify/";
    }

    public String getNotifyUrl(String sn) {
        if(sn.indexOf("SLJ") == 0){
            return "https://rongyaotupay.aokxm.com/api/shaliangjie/wechat/leshua/asyncNotify/" +sn;
        }
        return getSiteUrl() + sn;
    }

    public String getSign(Map<String, Object> params) throws Exception {
        // 签名步骤一：按字典序排序参数
        String str = WeiXinUtils.FormatBizQueryParaMap(params, false);
        // 签名步骤二：在string后加入KEY
        str += "&key=" + appSecret;
        // 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
        str = MD5Utils.getMD5Str(str).toUpperCase();
        return str;
    }

    public String getSignReturn(Map<String, Object> params) throws Exception {
        // 签名步骤一：按字典序排序参数
        String str = WeiXinUtils.FormatBizQueryParaMap(params, false);
        // 签名步骤二：在string后加入KEY
        str += "&key=" + returnAppSecret;
        // 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
        str = MD5Utils.getMD5Str(str).toUpperCase();
        return str;
    }

    public ResultVo getParameterMap(String sn, String body, String detail, BigDecimal amount, String openid, HttpServletRequest request) {
        Map<String, Object> params = new HashMap<String, Object>();
        Map<String, Object> resultMap = new HashMap<String, Object>();
        String createNoncestr = WeiXinUtils.CreateNoncestr();
        params.put("service", "get_tdcode");
        params.put("pay_way", "WXZF");
        params.put("merchant_id", merchantId);
        params.put("third_order_id", sn);
        // 这里写的金额为1 分到时修改
        params.put("amount", amount.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP).toString());
        params.put("jspay_flag", "3");
        params.put("appid",appId);
        params.put("sub_openid", openid);
        params.put("notify_url", URLEncoder.encode(getNotifyUrl(sn)));
        params.put("nonce_str", createNoncestr);
        params.put("body", StringUtils.abbreviate(body.replaceAll("[^0-9a-zA-Z\\u4e00-\\u9fa5 ]", ""), 30));
        try {
            String sign = getSign(params);
            params.put("sign", sign);
            String urlQueryParams = WeiXinUtils.FormatUrlQueryParaMap(params, true);
            logger.info("urlQueryParams:", urlQueryParams);
            HttpClient httpClient = new DefaultHttpClient();
            String url = micropayUrl + "?" + urlQueryParams;
            HttpPost httpPost = new HttpPost(url);
            //      httpPost.setEntity(new StringEntity(bizQueryParams, "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String result = EntityUtils.toString(response.getEntity(), "UTF-8");
            logger.info("result:" + result);
            resultMap = WeiXinUtils.doXMLParse(result);
            String status = (String) resultMap.get("result_code");
            if (StringUtils.isNotBlank(status) && "0".equals(status)) {
                HashMap<String, Object> finalpackage = new HashMap<String, Object>();
                String timestamp = WeiXinUtils.getTimeStamp();
                //{"appId":"wxeed21cfaecd5c41e","timeStamp":"1639734600","nonceStr":"22af0fc1a9344ba8a7c22d1aa23f8f47","package":"prepay_id=wx17175000788228c31000034cd45e350000","signType":"RSA","paySign":"DoTlVYO7a76KF4nFNBElvPkwOOGR816Ap1Fp3UJz5fgcHntVwTYK27Rli9Wksd6rLCfBUF4wOqK9TQfFedc5D/G09JK8fK9Zsj2eL1srr4Tszoi9w5mPsoQ8U6lPInJdaftsP6FXNcqDFCe5FfZ3R3reCblGgkpZ6d1imcRD3GMepsxeoLz5dT0wtgiFkYQl/DuaZOvAxZc0vL9BrQnIsXk0YHyLQuBGnuHxDhjLK/1pN0+OXzKgt9z9QCaXE73d39pla1eSArcyPk+kRorrjByUam6r0EkPgr3zPqCpDlS8mVmQwZYB2TiJIg+BZCCRyudjlRBeJbtDOG4TFV4PSw=="}
                String jspay_info_json = (String) resultMap.get("jspay_info");
                JSONObject jspay_info = JSON.parseObject(jspay_info_json);
                String packages = (String) jspay_info.get("package");
                String appId = (String) jspay_info.get("appId");
                String timeStamp = (String) jspay_info.get("timeStamp");
                String nonceStr = (String) jspay_info.get("nonceStr");
                String paySign = (String) jspay_info.get("paySign");
                String signType = (String) jspay_info.get("signType");
                finalpackage.put("appId", appId);
                finalpackage.put("timeStamp", timeStamp);
                finalpackage.put("nonceStr", nonceStr);
                finalpackage.put("package", packages);
                finalpackage.put("signType", signType);
                finalpackage.put("paySign", paySign);
//                finalpackage.put("appId", appId);
//                finalpackage.put("timeStamp", timestamp);
//                finalpackage.put("nonceStr", createNoncestr);
//                finalpackage.put("package", packages);
//                finalpackage.put("signType", "MD5");
//                String finalsign = getWeixinSign(finalpackage);
//                finalpackage.put("paySign", finalsign);
                return ResultVo.success(finalpackage, "成功");
            } else {
                String resp_code = (String) resultMap.get("resp_code");
                String resp_msg = (String) resultMap.get("resp_msg");
                return ResultVo.error(resp_code, resp_msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVo.error(ResultCode.FAIL);
        }
    }

    private String getWeixinSign(HashMap<String, Object> params) throws Exception {
        // 签名步骤一：按字典序排序参数
        String str = WeiXinUtils.FormatBizQueryParaMap(params, false);
        // 签名步骤二：在string后加入KEY
        str += "&key=" + smallSecret;
        // 签名步骤三：MD5加密 签名步骤四：所有字符转为大写
        str = MD5Utils.getMD5Str(str).toUpperCase();
        return str;
    }

    public String verifyNotify(String sn, BigDecimal amount, HttpServletRequest request) {
        String tradeSn = "";
        try {
            Map<String, Object> map = new HashMap();
            StringBuffer info = new StringBuffer();
            InputStream in = request.getInputStream();
            BufferedInputStream buf = new BufferedInputStream(in);
            byte[] buffer = new byte[1024];
            int iRead;
            while ((iRead = buf.read(buffer)) != -1) {
                info.append(new String(buffer, 0, iRead, "UTF-8"));
            }
            map = WeiXinUtils.doXMLParse(info.toString());
            if (map == null || map.isEmpty()) {
                return tradeSn;
            }
            // "amount":"990","attach":"","bank_type":"CMB_DEBIT","buyer_pay_amount":"990","channel_datetime":"2021-12-17 23:26:54","channel_order_id":"4200001409202112172096690380","coupon":"0","device_info":"WEB","discount_amount":"0","error_code":"0","goods_tag":"","leshua_order_id":"8001062780121351","merchant_id":"9960219801","openid":"o8uJ6uEQspuYPnijDUGrKy5KT1eM","out_transaction_id":"4200001409202112172096690380","pay_time":"2021-12-17 23:26:55","pay_way":"WXZF","settlement_amount":"990","sign":"55075735abd2e950941bd03d25e56f09","status":"2","sub_merchant_id":"479779456","sub_openid":"obuB_5LXPiC8EQZWyRKjgrdHUpIA","third_order_id":"OR20211217232647671","trade_type":"SmPgPay"
            logger.info("leshua 小程序支付回调:{}", JSONObject.toJSONString(map));
            if (map.get("status") != null && "2".equals(map.get("status"))) {
                String sign = getSignReturn(map);
                logger.info("leshua 小程序支付回调参数签名:{}", sign);
                if (/*sign.equals(map.get("sign"))
                        && */sn.equals(map.get("third_order_id"))
                        && merchantId.equals(map.get("merchant_id"))
                        && amount.multiply(new BigDecimal(100)).compareTo(new BigDecimal((String) map.get("amount"))) == 0) {
                    tradeSn = String.valueOf(map.get("leshua_order_id"));
                    return tradeSn;
                }
            }
            return tradeSn;
        } catch (Exception e) {
            e.printStackTrace();
            return tradeSn;
        }
    }

    public String getNotifyMessage() {
        return "000000";
    }
}
